// CoachKernel.h

// Jadro kouca, zakladne funkcie pre jeho funkcionalitu

#ifndef COACHKERNEL_H
#define COACHKERNEL_H

#include "Coach/Interfaces/CoachMemory.h"
#include "Coach/Interfaces/CoachSynchronization.h"
#include "Common/Protocol/CommandGen.h"
#include "Common/Tasks.h"
//#include "Common/Module.h"
//#include "Common/Main.h"
#include "Common/Support/Debug.h"

#include "Coach/CoachAnalyser.h"
//#include "Player/Formation.h"

// Kolko krat sa mame pokusat poslat timove logo?
#define TEAM_GRAPHIC_MAX_TRIES 20
// Kolko CLang sprav ukladame do FIFO buffera?
#define FIFO_BUFFER_SIZE 10
// Maximalna dlzka jednej CLang spravy
#define MAX_CLANG_STR_LEN 8154
// Kolko roznych dlzok nahravok rozlisujeme?
#define PASS_LEN_COUNT 3

// Rozlicne dlzky nahravok ( 0 <= passLens[0] <= passLens[1] ... > )
const float passLens[PASS_LEN_COUNT] = {5.0f, 10.0f, 20.0f};

#define NUM_FORMATIONS 6

enum
{
	FORMATION622 = 0,
	FORMATION532,
	FORMATION433,
	FORMATION523,
	FORMATION343,
	FORMATION334
};

const struct FORMATION
{
	int defs, mids, atts;
	char name[7];
} formation[NUM_FORMATIONS] =
{
	{6, 2, 2, "622"},
	{5, 3, 2, "532"},
	{4, 3, 3, "433"},
	{5, 2, 3, "523"},
	{3, 4, 3, "343"},
	{3, 3, 4, "334"}
};

#define NUM_ZONES 5

const struct ZONE
{
  float from, to;
} zones[NUM_ZONES] =
{
  {-52.5f, -36.0f},
  {-36.0f, -15.0f},
  {-15.0f,  15.0f},
  { 15.0f,  36.0f}, 
  { 36.0f,  52.5f}
};

// Hracova x-ova vzdialenost od lopty, ked sa povazuje za stredopoliara 
const float DIST_X_MID_FIELDER = 15.;

// Debugova statistika pre hracov
struct PLAYER_STATISTICS
{
	int shootsOnGoal;						// Pocet striel na branu
	float sumLenShootsOnGoal;				// Suma vsetkych dlzok striel na branu
	int passesAll[PASS_LEN_COUNT + 1];		// Pocty vsetkych nahravok pre vsetky dlzky
	int passesSuccess[PASS_LEN_COUNT + 1];	// Pocty uspesnych nahravok pre vsetky dlzky
	float sumPassSucLen;					// Suma vsetkych dlzok uspesnych nahravok
	int passesReceived;						// Pocet prijatych nahravok
	int interceptions;						// Pocet prerusenych nahravok
	int cyclesWithBall;						// Pocet cyklov, kedy ma hrac loptu (kickable)
	Vector sumDistFromBall;					// Suma vzdialenosti od lopty v sucasnom cykle
	float sumSpeedNearBall;					// Suma rychlosti, ked je lopta blizko
	int cyclesNearBall;						// Pocet cyklov, ked je lopta blizko
	int cyclesAttacker;						// Kolko cyklov ho povazujeme za utocnika 
	int cyclesDefender;						// Kolko cyklov ho povazujeme za obrancu
	int cyclesMidfielder;					// Kolko cyklov ho povazujeme za stredopoliara
};

// Co znamena "lopta je blizko" v metroch?
const float BALL_NEAR_DIST = 3.0f;

// Aka je minimalne pozadovana rychlost lopty na brankovej ciare (aby sa detekovali strely na branku?)
const float SPEED_ON_GOAL_LINE_MIN = 0.1f;

// Debugova statistika lopty
struct BALL_STATISTICS
{
	int cyclesOnOurHalf;		// Kolko cyklov bola lopta na nasej polovici?
	int cyclesOnTheirHalf;		// Kolko cyklov bola na superovej polovici?
  int cyclesInZone[NUM_ZONES];	// Kolko cyklov bola lopta v kazdej zone?
};

// Kto kopol do lopty, kedy a kde to bolo?
struct KICK_INFO
{
	int who;	// 0: nikto, 1 - 11: nas hrac, 2 - 22: superov hrac
	int when;   // V ktorom cykle bolo do lopty kopnute?
	Point from; // Kde bolo do lopty kopnute?
};

// Jadro kouca (vsetko v jednom) -> synchronizacia, model sveta a simulacne parametre
class CoachKernel : public Module, public CoachMemoryInterface, public CoachSynchronizationInterface
{
	// Generator prikazov
	CommandGen* commandGen;

	// Koordinaty vlajok
	Point flagPos[56];

	// Statistika pre nasich hracov 1 - 11
	PLAYER_STATISTICS statsOurPlayer[12];

	// Statistika pre superovych hracov 1 - 11
	PLAYER_STATISTICS statsTheirPlayer[12];

	// Statistika lopty
	BALL_STATISTICS statsBall;

	int advice; 
	int nHeteroCounter;
	int nZmenaTypov;

	int cornerKicksOur;						// Pocet nasich rohovych kopov
	int cornerKicksTheir;					// Pocet superovych rohovych kopov
	int offsidesOur;						// Pocet nasich postaveni mimo hry
	int offsidesTheir;						// Pocet superovych postaveni mimo hry

//	/// Synchronization
//	const SENSE_BODY* m_pLastSB;
//	const VISUAL_INFO* m_pLastVI;
//	bool m_bDecisionWasMade;

//	/// Synchronization mode
//	//@{
//	SynchroMode m_iSynchMode;
//	SynchroMode m_iNextSynchMode;
//	//@}

protected:
	
	int canSendCLmessage;			// Ak je == 0, mozme poslat CLang spravu (pouzivame iba definovane spravy)
	int continousTimeInPlayOn;		// Kolko cyklov po sebe trval PlayOn mod
	COACH_BALL lastBallInfo;		// Posledna informacia o lopte
	KICK_INFO lastKick;				// Na detekciu nahravok, kto, kedy a kde kopol do lopty
	int lastNearestPlayer;			// Hrac najblizsie k lopte v predchadzajucom cykle. Ked sa detekuje kopnutie do lopty,
									// predpokladame, ze tento hrac kopol do lopty. 0: nikto, 1 - 11: na hrac, 12 -22: superov hrac (cislo - 11)	
	bool ourSide;					// true: lava strana, false: prava strana
	PLAYER_PARAMS* playerParams;	// Informacie o hetero hracoch (NULL, ak ziadne nie su)
	PLAYER_TYPE* playerTypes;		// Informacie o typoch hraca (NULL, ak ziadne nie su)
	int playerTypesByNumber[12];	// Typy hracov podla ich cisiel (1 - 11)
	PlayMode playMode;				// Herny mod
	int sayCoachCnt;				// Kolko freeform sprav sme poslali
	int scoreOur;					// Nase skore
	int scoreTheir;					// Skore supera
	SERVER_PARAMS* serverParams;	// Informacie o parametroch servera (NULL, ak ziadne nie su)
	int simTime;					// Simulacny cas
	int timeInPlayOn;				// Kolko cyklov trval PlayOn mod
	int timeOfLastVisualInfo;		// Cas prichodu poslednej VI

	CoachAnalyser analyser;
	Formation formations;
	
	int FIFObottom, FIFOtop;
	char FIFObuffer[FIFO_BUFFER_SIZE + 1][MAX_CLANG_STR_LEN];
	
		
	// Ak nie je mozne poslat spravu kvoli limitovanej komunikacii vrati sa 0, inak > 0
	int CanSendMessage();

	// Vrati ocakavanu formaciu timu
	// parameter our == true -> nasa formacia 
	int GetFormation(bool our);

	// Vrati index podla dlzky
	int GetLengthIndex(float dist)
	{
		static int i;
		
		for(i = 0; i < PASS_LEN_COUNT; i++)
			if(dist <= passLens[i])
				return i;
		return i;
	}

	// Je zastaveny simulacny cas?
	bool IsTimeStoped() const;

	// Naplni to FIFO buffer a posle prvu spravu, ked je to mozne. Ked je FIFO buffer plny, prva sprava je nahradena.
	// Ak msg je NULL, tak sa pokusi poslat prvu spravu (ak nejaka je)
	void SayMessage(const char* msg);

	// Timova grafika 
	
	// Ktore casti loga uz boli poslane?
	char teamGraphicDir[512];
	bool teamGraphicOk[32][8];
	int teamGraphicOkCount;
	int teamGraphicTries;

	// Posle logo na server
	bool SendTeamGraphic(const char* path);

public:

	// Konstruktor
	CoachKernel(const char* name = "CoachKernel", const char* desc = "CoachKernel module");
	// Destruktor
	virtual ~CoachKernel();

	// Implementacia rozhrania
	virtual Interface* GetInterface(int task) const;
	virtual int Init(int argc, char **argv, int iTask = -1);
	void Run(int iTask = -1) {};

	// HANDLERY

	// Handler pre spravy 'ok team_graphic'
	virtual void OnOkTeamGraphic(int x, int y);

	// Simulacne parametre
	virtual void OnServerParam(const SERVER_PARAMS* params);
	virtual void OnPlayerParam(const PLAYER_PARAMS* params);
	virtual void OnPlayerType(int id, const PLAYER_TYPE* type);

	// Vnimanie a model sveta
	virtual void OnInit(bool side);
	virtual void OnChangeMode(int time, PlayMode mode);
	virtual void OnHear(int time, bool our, int uniformNumber, const char* message);
	virtual void OnScore(int time, unsigned our, unsigned their);
	virtual void OnSeeGlobal(const COACH_VISUAL_INFO* vi);
	virtual void OnChangePlayerType(unsigned number, int type);
	
	// Pamat kouca
	virtual int GetSimTime() const			{ return simTime; }
	virtual PlayMode GetPlayMode() const	{ return playMode; }
	virtual unsigned GetOurScore() const	{ return scoreOur; }
	virtual unsigned GetTheirScore() const	{ return scoreTheir; }
	virtual int GetTypeByNumber(unsigned number) const { return playerTypesByNumber[number]; }

	// METODY

	//
	float CalcRealSpeedMax(int type);
	//
	void MakePlayerSelection();
	

};

#endif // COACHKERNEL_H
